<script setup lang="ts">
import {add, del, getForm, getPage, mockRun, run, switchStatus, update} from "@/api/crawl/template";

import {
	CrawlTemplateForm,
	CrawlTemplateMockForm,
	CrawlTemplatePageVO,
	CrawlTemplateQuery
} from "@/api/crawl/template/types";
import CrawlTimePicker from "@/components/Crawl/CrawlTimePicker.vue"
import CrawlNamespaceSelector from "@/components/Crawl/CrawlNamespaceSelector.vue"
import CrawlTemplateEditor from "@/components/Crawl/CrawlTemplateEditor.vue"
import CrawlTemplateMockView from "@/components/Crawl/CrawlTemplateMockView.vue"
import {DialogModeEnum} from '@/enums/DialogModeEnum';
import {CrawlTemplateStatusEnum} from '@/enums/CrawlTemplateStatusEnum';
import {ref} from "vue";

const queryFormRef = ref(ElForm);
const dataFormRef = ref(ElForm);
const mockDataFormRef = ref(ElForm);

const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const opMode = ref(DialogModeEnum.CLOSE)

const queryParams = reactive<CrawlTemplateQuery>({
	pageNum: 1,
	pageSize: 10,
});

const dataList = ref<CrawlTemplatePageVO[]>();

const dialog = reactive<DialogOption>({
	visible: false,
});
const mockDialog = reactive<DialogOption>({
	visible: false,
});

const formData = reactive<CrawlTemplateForm>({
	nsCode: "",
	tmplCode: "",
	tmplName: "",
	seedUrl: "",
	schedHour: 24,
	pageable: false,
	pagingLimit: 1,
	pagingSelectorTmpl: "",
	pagingListTmpl: "",
	pageDetailTmpl: "",
	schedPriority: 0,
	tmplStatus: 1,
	approveStatus: 1,
});

const mockFormData = reactive<CrawlTemplateMockForm>({
	nsCode: "",
	seedUrl: "",
	tmplName: "",
	dataJson: "",
	pageable: false,
	headers: "",
});

const mockCrawlPageable = ref(true)

const rules = reactive({
	nsName: [{required: true, message: "请输入名称", trigger: "blur"}],
});

const mockRules = reactive({
	nsName: [{required: true, message: "请输入名称", trigger: "blur"}],
});

const nsSelector = ref()
const timePicker = ref()

/**
 * 查询
 */
function handleQuery() {
	loading.value = true;
	getPage(queryParams)
			.then(({data}) => {
				dataList.value = data.list;
				total.value = data.total;
			})
			.finally(() => {
				loading.value = false;
			});
}

/**
 * 重置查询
 */
function resetQuery() {
	queryFormRef.value.resetFields();
	queryParams.pageNum = 1;
	queryParams.nsCode = '';

	queryParams.createTimeStart = undefined
	queryParams.createTimeEnd = undefined
	nsSelector.value.reset();
	timePicker.value.reset();
	handleQuery();
}

/**
 * 行checkbox change事件
 */
function handleSelectionChange(selection: any) {
	ids.value = selection.map((item: any) => item.id);
}

/**
 * 打开表单弹窗
 *
 * @param dataId 数据ID
 */
function openDialog(dataId?: number) {
	if (dataId) {
		dialog.title = "修改数据";
		getForm(dataId).then(({data}) => {
			Object.assign(formData, data);
		});
		opMode.value = DialogModeEnum.EDIT;
	} else {
		dialog.title = "新增数据";
		opMode.value = DialogModeEnum.ADD;
	}
	dialog.visible = true;
}

/**
 * 打开Mock表单弹窗
 *
 * @param dataId 数据ID
 */
function openMockDialog() {
	const dataIds = ids.value;
	if (!dataIds) {
		ElMessage.warning("请勾选删除项");
		return;
	}

	if (dataIds.length > 1) {
		ElMessage.warning("仅能勾选一项");
		return;
	}

	mockDialog.title = "模拟执行";
	opMode.value = DialogModeEnum.EDIT;
	if (dataIds[0]) {
		getForm(dataIds[0]).then(({data}) => {
			Object.assign(mockFormData, data);
			mockCrawlPageable.value = mockFormData.pageable
		}).finally(() => {
			mockDialog.visible = true
		});
	}
}

/**
 * 表单提交
 */
function handleSubmit() {
	loading.value = false;
	dataFormRef.value.validate((isValid: boolean) => {
		if (isValid) {
			const dataId = formData.id;
			if (dataId) {
				update(dataId, formData)
						.then(() => {
							ElMessage.success("修改成功");
							closeDialog();
							handleQuery();
						})
						.finally(() => (loading.value = false));
			} else {
				add(formData)
						.then(() => {
							ElMessage.success("新增成功");
							closeDialog();
							handleQuery();
						})
						.finally(() => (loading.value = false));
			}
		}
	});
}

/**
 * 表单Mock提交
 */
function handleMockSubmit() {
	loading.value = true;
	mockRun(mockFormData).then(({data}) => {
		mockFormData.dataJson = data;
	}).finally(() => {
		loading.value = false;
	});
}

/**
 * 关闭弹窗
 */
function closeDialog() {
	dialog.visible = false;
	opMode.value = DialogModeEnum.CLOSE;
	resetForm();
}

/**
 * 关闭Mock弹窗
 */
function closeMockDialog() {
	mockDialog.visible = false;
	opMode.value = DialogModeEnum.CLOSE;
	resetMockForm();
}

/**
 * 重置表单
 */
function resetForm() {
	nsSelector.value.reset();
	dataFormRef.value.resetFields();
	dataFormRef.value.clearValidate();

	formData.id = undefined;
	formData.nsCode = "";
	formData.tmplCode = "";
	formData.tmplName = "";
	formData.seedUrl = "";
	formData.schedHour = 24;
	formData.pageable = false;
	formData.pagingLimit = 1;
	formData.pagingSelectorTmpl = "";
	formData.pagingListTmpl = "";
	formData.pageDetailTmpl = "";
	formData.schedPriority = 0;
	formData.tmplStatus = 1;
	formData.approveStatus = 0;
	formData.remark = "";
}

/**
 * 重置Mock表单
 */
function resetMockForm() {
	mockFormData.nsCode = "";
	mockFormData.tmplName = "";
	mockFormData.dataJson = "";
	mockFormData.headers = "";
}

/**
 * 删除
 */
function handleDelete(dataId?: number) {
	const dataIds = [dataId || ids.value].join(",");
	if (!dataIds) {
		ElMessage.warning("请勾选删除项");
		return;
	}

	ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
		confirmButtonText: "确定",
		cancelButtonText: "取消",
		type: "warning",
	}).then(() => {
		del(dataIds).then(() => {
			ElMessage.success("删除成功");
			resetQuery();
		});
	});
}

/**
 * 执行一次
 */
function handleRunOnce(dataId: number) {
	ElMessageBox.confirm("确认执行已选中的任务?", "提示", {
		confirmButtonText: "确定",
		cancelButtonText: "取消",
		type: "success",
	}).then(() => {
		run(dataId).then(() => {
			ElMessage.success("操作成功");
		});
	});
}

/**
 * 切换状态
 */
function handleSwitchStatus(dataId: number) {
	switchStatus(dataId).then(() => {
		ElMessage.success("操作成功");
		resetQuery();
	});
}

function onSelectNsCode(nsCode: string) {
	queryParams.nsCode = nsCode;
}

function onFormSelectNsCode(nsCode: string) {
	formData.nsCode = nsCode;
}

function onPagingListTmplEdit(xmlContent: any) {
	formData.pagingListTmpl = xmlContent;
}

function onPagingSelectorTmplEdit(xmlContent: any) {
	formData.pagingSelectorTmpl = xmlContent;
}

function onPageDetailTmplEdit(xmlContent: any) {
	formData.pageDetailTmpl = xmlContent;
}

const pagingListTmplEditor = ref()
const pagingSelectorTmplEditor = ref()
const pageDetailTmplEditor = ref()
const mockView = ref()

const openPagingListTmplEditor = () => {
	pagingListTmplEditor.value.showEditor()
}
const openPagingSelectorTmplEditor = () => {
	pagingSelectorTmplEditor.value.showEditor()
}
const openPageDetailTmplEditor = () => {
	pageDetailTmplEditor.value.showEditor()
}

function onSelectTimeRange(timeRange: [Date, Date]) {
	if (timeRange === null) {
		queryParams.createTimeStart = undefined;
		queryParams.createTimeEnd = undefined;
		return;
	}
	queryParams.createTimeStart = timeRange[0];
	queryParams.createTimeEnd = timeRange[1];
}

onMounted(() => {
	handleQuery();
});
</script>

<template>
	<div class="app-container">
		<div class="search">
			<el-form ref="queryFormRef" :model="queryParams" :inline="true">
				<CrawlNamespaceSelector ref="nsSelector" @on-select="onSelectNsCode"/>
				<el-form-item label="模板编码" prop="tmplCode">
					<el-input
							v-model="queryParams.tmplCode"
							placeholder="请输入..."
							clearable
							@keyup.enter="handleQuery"
					/>
				</el-form-item>
				<CrawlTimePicker ref="timePicker" @on-select="onSelectTimeRange"/>
				<el-form-item>
					<el-button type="primary" @click="handleQuery()">
						<i-ep-search/>
						搜索
					</el-button>
					<el-button @click="resetQuery()">
						<i-ep-refresh/>
						重置
					</el-button>
				</el-form-item>
			</el-form>
		</div>

		<el-card shadow="never">
			<template #header>
				<el-button type="success" @click="openDialog()">
					<i-ep-plus/>
					新增
				</el-button>
				<el-button
						type="danger"
						:disabled="ids.length === 0"
						@click="handleDelete()">
					<i-ep-delete type="danger"/>
					删除
				</el-button>
				<el-button
						type="primary"
						:disabled="ids.length === 0"
						@click="openMockDialog()">
					<i-ep-video-play/>
					模拟执行
				</el-button>
			</template>
			<el-table
					highlight-current-row
					:data="dataList"
					v-loading="loading"
					@selection-change="handleSelectionChange"
					border>
				<el-table-column type="selection" width="55" align="center"/>
				<el-table-column label="空间" prop="nsCode,nsName">
					<template #default="scope">
						<span>{{ scope.row.nsName }}</span><br>
						<span style="color: #8492a6; font-size: 12px">{{ scope.row.nsCode }}</span>
					</template>
				</el-table-column>
				<el-table-column label="模板" prop="tmplCode" min-width="100">
					<template #default="scope">
						<span>{{ scope.row.tmplName }}</span><br>
						<span style="color: #8492a6; font-size: 12px">{{ scope.row.tmplCode }}</span>
					</template>
				</el-table-column>
				<el-table-column label="种子URL" prop="seedUrl" min-width="200" :show-overflow-tooltip="true"/>
				<el-table-column :label="'间隔小时\n&优先级'" prop="schedHour">
					<template #default="scope">
						{{ scope.row.schedHour }}h / {{ scope.row.schedPriority }}
					</template>
				</el-table-column>
				<el-table-column label="备注" prop="remark" align="center" min-width="100" :show-overflow-tooltip="true"/>
				<el-table-column label="创建时间" prop="createTime" min-width="140"/>
				<el-table-column label="状态" align="center">
					<template #default="scope">
						<el-switch
								v-model="scope.row.tmplStatus"
								:active-value=CrawlTemplateStatusEnum.OPEN
								:inactive-value=CrawlTemplateStatusEnum.CLOSE
								@change="handleSwitchStatus(scope.row.id)"
								active-color="#13ce66"
								inactive-color="#ff4949">
						</el-switch>
					</template>
				</el-table-column>
				<el-table-column fixed="right" label="操作" align="center" width="100">
					<template #default="scope">
						<el-button
								type="primary"
								link
								size="small"
								@click.stop="handleRunOnce(scope.row.id)">
							<i-ep-caret-right/>
							执行一次
						</el-button>
						<el-button
								type="primary"
								link
								size="small"
								@click.stop="openDialog(scope.row.id)">
							<i-ep-edit/>
							编辑
						</el-button>
						<el-button
								type="danger"
								link
								size="small"
								@click.stop="handleDelete(scope.row.id)"
						>
							<i-ep-delete/>
							删除
						</el-button>
					</template>
				</el-table-column>
			</el-table>

			<pagination
					v-if="total > 0"
					v-model:total="total"
					v-model:page="queryParams.pageNum"
					v-model:limit="queryParams.pageSize"
					@pagination="handleQuery"
			/>
		</el-card>

		<el-dialog
				:title="dialog.title"
				v-model="dialog.visible"
				width="1000px"
				@close="closeDialog">

			<CrawlTemplateEditor ref="pagingListTmplEditor" :content="formData.pagingListTmpl"
													 @on-edit="onPagingListTmplEdit"/>
			<CrawlTemplateEditor ref="pagingSelectorTmplEditor" :content="formData.pagingSelectorTmpl"
													 @on-edit="onPagingSelectorTmplEdit"/>
			<CrawlTemplateEditor ref="pageDetailTmplEditor" :content="formData.pageDetailTmpl"
													 @on-edit="onPageDetailTmplEdit"/>
			<el-form
					ref="dataFormRef"
					:model="formData"
					:rules="rules"
					label-width="150px">

				<CrawlNamespaceSelector
						ref="nsSelector"
						@on-select="onFormSelectNsCode"
						:def-ns-code="formData.nsCode"
						:op-mode="opMode"/>
				<el-form-item label="模板编码" prop="tmplCode">
					<el-input
							:disabled="true"
							v-model="formData.tmplCode"
							style="width: 50%;"
							placeholder="后端生成，无需输入"/>
				</el-form-item>
				<el-form-item label="模板名称" prop="tmplName">
					<el-input v-model="formData.tmplName" style="width: 50%;" placeholder="请输入..."/>
				</el-form-item>
				<el-form-item label="种子URL" prop="seedUrl">
					<el-input v-model="formData.seedUrl" style="width: 93%;" placeholder="请输入..."/>
				</el-form-item>
				<el-form-item label="间隔小时" prop="schedHour">
					<el-input-number v-model="formData.schedHour" :min="1"/>
				</el-form-item>
				<el-form-item label="页面类型" prop="pageable">
					<el-radio-group v-model="formData.pageable">
						<el-radio :label="true">可分页</el-radio>
						<el-radio :label="false">仅详情</el-radio>
					</el-radio-group>
				</el-form-item>
				<el-form-item
						v-if="formData.pageable === true"
						label="分页限制"
						prop="pagingLimit"
				>
					<el-input-number v-model="formData.pagingLimit" :min="1" :max="20"/>
				</el-form-item>
				<el-divider content-position="left">XSLT解析模板</el-divider>
				<el-form-item
						v-if="formData.pageable === true"
						label="列表页XSLT"
						prop="pagingListTmpl">
					<el-input
							:disabled="true"
							v-model="formData.pagingListTmpl"
							style="width: 93%;"
							placeholder="请编辑XSLT模板"
					/>
					<el-button
							type="primary"
							link
							size="small"
							@click="openPagingListTmplEditor"
					>
						<i-ep-edit class="xslt-edit-button"/>
						编辑
					</el-button>
				</el-form-item>
				<el-form-item
						v-if="formData.pageable === true"
						label="分页器XSLT"
						prop="pagingSelectorTmpl">
					<el-input
							:disabled="true"
							v-model="formData.pagingSelectorTmpl"
							style="width: 93%;"
							placeholder="请编辑XSLT模板"
					/>
					<el-button
							type="primary"
							link
							size="small"
							@click="openPagingSelectorTmplEditor"
					>
						<i-ep-edit class="xslt-edit-button"/>
						编辑
					</el-button>
				</el-form-item>
				<el-form-item
						label="详情页XSLT"
						prop="pageDetailTmpl">
					<el-input
							:disabled="true"
							v-model="formData.pageDetailTmpl"
							style="width: 93%;"
							placeholder="请编辑XSLT模板"
					/>
					<el-button
							type="primary"
							link
							size="small"
							@click="openPageDetailTmplEditor"
					>
						<i-ep-edit class="xslt-edit-button"/>
						编辑
					</el-button>
				</el-form-item>
				<el-divider></el-divider>
				<el-form-item label="任务优先级" prop="schedPriority">
					<el-input-number
							v-model="formData.schedPriority"
							:min="0"
							:max="10"
					/>
				</el-form-item>
				<el-form-item label="状态" prop="tmplStatus">
					<el-switch
							v-model="formData.tmplStatus"
							:active-value=CrawlTemplateStatusEnum.OPEN
							:inactive-value=CrawlTemplateStatusEnum.CLOSE
							active-color="#13ce66"
							inactive-color="#ff4949">
					</el-switch>
				</el-form-item>
				<el-form-item label="备注" prop="remark">
					<el-input
							v-model="formData.remark"
							type="textarea"
							placeholder="备注"
							style="width: 93%;"
							:autosize="{ minRows: 2, maxRows: 4 }"
					/>
				</el-form-item>
			</el-form>
			<template #footer>
				<div class="dialog-footer">
					<el-button type="primary" @click="handleSubmit">确 定</el-button>
					<el-button @click="closeDialog">取 消</el-button>
				</div>
			</template>
		</el-dialog>

		<el-dialog
				:title="mockDialog.title"
				v-model="mockDialog.visible"
				width="1000px"
				@close="closeMockDialog">

			<el-form
					ref="mockDataFormRef"
					:model="mockFormData"
					:rules="mockRules"
					label-width="100px">
				<CrawlNamespaceSelector
						ref="nsSelector"
						@on-select="onFormSelectNsCode"
						:def-ns-code="mockFormData.nsCode"
						:op-mode="opMode"/>
				<el-form-item label="模板名称" prop="tmplName">
					<el-input v-model="mockFormData.tmplName" disabled style="width: 50%;"/>
				</el-form-item>
				<el-form-item label="抓取类型" prop="tmplName">
					<el-radio-group v-model="mockFormData.pageable">
						<el-radio :label="true" v-if="mockCrawlPageable===true">列表页</el-radio>
						<el-radio :label="false">详情页</el-radio>
					</el-radio-group>
				</el-form-item>
				<el-form-item label="种子URL" prop="seedUrl">
					<el-input v-model="mockFormData.seedUrl"/>
				</el-form-item>
				<el-form-item label="请求头" prop="headers">
					<el-input
							v-model="mockFormData.headers"
							type="textarea"
							placeholder="冒号分隔，一行一对。（可直接从浏览器调试面板的请求报文里拷贝）"
							:autosize="{ minRows: 2, maxRows: 4 }"
					/>
				</el-form-item>
				<el-divider content-position="left">抓取数据展示</el-divider>
				<CrawlTemplateMockView
						ref="mockView"
						:content="mockFormData.dataJson"/>
			</el-form>
			<template #footer>
				<div class="dialog-footer">
					<el-button type="primary" @click="handleMockSubmit">执 行</el-button>
					<el-button @click="closeMockDialog">取 消</el-button>
				</div>
			</template>
		</el-dialog>

	</div>
</template>

<style lang="scss" scoped>
.xslt-edit-button {
	margin-left: 10px;
}
</style>
